package org.springblade.common.utils;



import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import org.apache.commons.lang.time.FastDateFormat;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DateTimeException;
import java.util.*;

/**
 * <p>时间处理工具类</p>
 */
public class DateUtils {

    public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_DAY_2 = "yyyy/MM/dd";
    public static final String TIME_FORMAT_SEC = "HH:mm:ss";
    public static final String DATE_FORMAT_SEC = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_MSEC = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    public static final String DATE_FORMAT_DAY_SIMPLE = "y/M/d";

    /**
     * 匹配yyyy-MM-dd
     */
    private static final String DATE_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配yyyy/MM/dd
     */
    private static final String DATE_REG_2 = "^[1-9]\\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配y/M/d
     */
    private static final String DATE_REG_SIMPLE_2 = "^[1-9]\\d{3}/([1-9]|1[0-2])/([1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配HH:mm:ss
     */
    private static final String TIME_SEC_REG = "^(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    /**
     * 匹配yyyy-MM-dd HH:mm:ss
     */
    private static final String DATE_TIME_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    /**
     * 匹配yyyy-MM-dd HH:mm:ss.SSS
     */
    private static final String DATE_TIME_MSEC_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    /**
     * 匹配yyyy-MM-dd'T'HH:mm:ss.SSS
     */
    private static final String DATE_TIME_MSEC_T_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    /**
     * 匹配yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
     */
    private static final String DATE_TIME_MSEC_T_Z_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}Z$";

    /**
     * <p>将{@link Date}类型转换为指定格式的字符串</p>
     * author : Crab2Died
     * date   : 2017年06月02日  15:32:04
     *
     * @param date   {@link Date}类型的时间
     * @param format 指定格式化类型
     * @return 返回格式化后的时间字符串
     */
    public static String date2Str(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * <p>将{@link Date}类型转换为默认为[yyyy-MM-dd HH:mm:ss]类型的字符串</p>
     * author : Crab2Died
     * date   : 2017年06月02日  15:30:01
     *
     * @param date {@link Date}类型的时间
     * @return 返回格式化后的时间字符串
     */
    public static String date2Str(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_SEC);
        return sdf.format(date);
    }

    /**
     * <p>根据给出的格式化类型将时间字符串转为{@link Date}类型</p>
     * author : Crab2Died
     * date   : 2017年06月02日  15:27:22
     *
     * @param strDate 时间字符串
     * @param format  格式化类型
     * @return 返回{@link java.util.Date}类型
     */
    public static Date str2Date(String strDate, String format) {
        Date date = null;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            date = sdf.parse(strDate);
        } catch (ParseException e) {
            throw new DateTimeException("[" + strDate + "] parse to [" + format + "] exception", e);
        }
        return date;
    }


	// 获取当前时间所在年的周数
	public static int getWeekOfYear(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);
		return c.get(Calendar.WEEK_OF_YEAR);
	}
	// 获取当前时间所在年的最大周数
	public static int getMaxWeekNumOfYear(int year) {
		Calendar c = new GregorianCalendar();
		c.set(year, Calendar.DECEMBER, 31, 23, 59, 59);
		return getWeekOfYear(c.getTime());
	}
	// 获取某年的第几周的开始日期
	public static String getFirstDayOfWeek(int year, int week) {
		Calendar c = new GregorianCalendar();
		c.set(Calendar.YEAR, year);
		c.set(Calendar.MONTH, Calendar.JANUARY);
		c.set(Calendar.DATE, 1);
		Calendar cal = (GregorianCalendar) c.clone();
		cal.add(Calendar.DATE, week * 7);
		DateFormat df = new SimpleDateFormat(DATE_FORMAT_DAY);
		return df.format(getFirstDayOfWeek(cal.getTime()));
	}
	// 获取某年的第几周的结束日期
	public static String getLastDayOfWeek(int year, int week) {
		Calendar c = new GregorianCalendar();
		c.set(Calendar.YEAR, year);
		c.set(Calendar.MONTH, Calendar.JANUARY);
		c.set(Calendar.DATE, 1);
		Calendar cal = (GregorianCalendar) c.clone();
		cal.add(Calendar.DATE, week * 7);
		DateFormat df = new SimpleDateFormat(DATE_FORMAT_DAY);
		return df.format(getLastDayOfWeek(cal.getTime()));
	}

	/**
	 * 获取指定日期所在周的第一天
	 * @return
	 * @throws Exception
	 */
	public static Date getFirstDayOfWeek(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek()); // Monday
		return c.getTime();
	}
	/**
	 * 获取指定日期所在周的最后一天
	 * @return
	 * @throws Exception
	 */
	public static Date getLastDayOfWeek(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6); // Sunday
		return c.getTime();
	}
	/**
	 * 获取指定日期所在周的第几天0-6
	 * @return
	 * @throws Exception
	 */
	public static Date getDayOfWeek(Date date, int n) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + n);
		return c.getTime();
	}

	/**
	 * 根据日期获取周及周开始日期
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static List<String> getWeeks(Date startDate,Date endDate){
		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

		Calendar c1=Calendar.getInstance();
		c1.setTime(startDate);
		//转为周一
		int weekYear = c1.get(Calendar.YEAR);
		int weekOfYear = c1.get(Calendar.WEEK_OF_YEAR);
		c1.setWeekDate(weekYear, weekOfYear, Calendar.MONDAY);
		Calendar c2=Calendar.getInstance();
		c2.setTime(endDate);
		int weekYear2 = c2.get(Calendar.YEAR);
		int weekOfYear2 = c2.get(Calendar.WEEK_OF_YEAR);
		c2.setWeekDate(weekYear2, weekOfYear2, Calendar.SUNDAY);
		List<String> resultList = new ArrayList<>();
		while (true) {
			resultList.add(sdf.format(c1.getTime())+","+c1.get(Calendar.WEEK_OF_YEAR));
			if(c1.getTimeInMillis()>=c2.getTimeInMillis()){
				break;
			}
			//增加7天
			c1.setTimeInMillis(c1.getTimeInMillis()+1000*60*60*24*7);
		}
		return resultList;
	}

	/**
	 * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致
	 *
	 * @param nowTime 当前时间
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @return
	 * @author shiwei
	 */
	public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
		if (nowTime.getTime() == startTime.getTime()
			|| nowTime.getTime() == endTime.getTime()) {
			return true;
		}

		Calendar date = Calendar.getInstance();
		date.setTime(nowTime);

		Calendar begin = Calendar.getInstance();
		begin.setTime(startTime);

		Calendar end = Calendar.getInstance();
		end.setTime(endTime);

		if (date.after(begin) && date.before(end)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 判断当前时间是否大于结束时间
	 * @param nowDate 开始时间
	 * @param endDate 结束时间
	 * @return
	 */
	public static boolean equalsDate(Date nowDate , Date endDate){
		if (nowDate.getTime() == endDate.getTime()){
			return true;
		}
		Calendar date = Calendar.getInstance();
		date.setTime(nowDate);
		Calendar end = Calendar.getInstance();
		end.setTime(endDate);
		if (date.after(end)){
			return true;
		} else {
			return false;
		}
	}
	/**
	 * 判断当前区间段是否在另一个区间段中
	 * @return
	 * @throws Exception
	 */

	public static  boolean judge(Date startTime, Date endTime, Date start, Date end){
		if((startTime.getTime()<=start.getTime()) &&
			endTime.getTime()>=start.getTime()){
			return true;
		}else if((startTime.getTime()>=start.getTime())&&
			startTime.getTime()<=end.getTime()){
			return true;
		}else{
			return false;
		}
	}

	/**
	 * 根据日期计算天数，获取的是绝对值
	 * @return
	 * @throws Exception
	 */
	public static long daysBetween(Date one, Date two) {
		long difference =  (one.getTime()-two.getTime())/86400000;
		return Math.abs(difference);
	}

	/**
	 * 根据日期获取第多少周
	 * @return
	 * @throws Exception
	 */
	public static int getWeeks(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int weeks = calendar.get(Calendar.WEEK_OF_YEAR);
		return weeks;
	}


    /**
     * 根据出生年月 计算年龄
     * @param birthDay
     * @return
     * @throws Exception
     */

    public static  int getAge(Date birthDay) throws Exception {
        Calendar cal = Calendar.getInstance();
        if (cal.before(birthDay)) { //出生日期晚于当前时间，无法计算
            throw new IllegalArgumentException(
                    "The birthDay is before Now.It's unbelievable!");
        }
        int yearNow = cal.get(Calendar.YEAR);  //当前年份
        int monthNow = cal.get(Calendar.MONTH);  //当前月份
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
        cal.setTime(birthDay);
        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
        int age = yearNow - yearBirth;   //计算整岁数
        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前，年龄减一
            }else{
                age--;//当前月份在生日之前，年龄减一

            }
        }
        return age;
    }


	/**
	 * 得到当前日期字符串 格式（yyyy-MM-dd）
	 */
	public static String getDate() {
		return getDate("yyyy-MM-dd");
	}

	/**
	 * 得到当前日期字符串 格式（yyyy-MM-dd） pattern可以为："yyyy-MM-dd" "HH:mm:ss" "E"
	 */
	public static String getDate(String pattern) {
//		return DateFormatUtils.format(new Date(), pattern);
		return FastDateFormat.getInstance(pattern).format(new Date());
	}

	/**
	 * 获取近一周的第一天
	 * @return
	 */
	public static String getWeekFirstDay(Date date){
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_DAY);//可以方便地修改日期格式
		Calendar calendar = Calendar.getInstance();
//		calendar.add(Calendar.MONTH,0);
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR)- 6);
		return sdf.format(calendar.getTime());
	}

	/**
	 * 获取近一个月的第一天
	 * @return
	 */
	public static String getMonthFirstDay(){
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_DAY);//可以方便地修改日期格式
		Calendar calendar = Calendar.getInstance();
//		calendar.add(Calendar.MONTH,0);
		calendar.set(Calendar.MONTH,calendar.get(Calendar.MONTH) - 1);
		return sdf.format(calendar.getTime());
	}

	/**
	 * 获取当前季度第一天
	 * @return
	 */
	public static String getQuarterFirstDay(){
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_DAY);
		Calendar c = Calendar.getInstance();
		c.set(Calendar.MONTH,c.get(Calendar.MONTH) - 3);
		return sdf.format(c.getTime());
//		int month = c.get(c.MONTH) + 1;
//		int quarter = 0;
//		if (month >= 1 && month <= 3) {
//			quarter = 1;
//		} else if (month >= 4 && month <= 6) {
//			quarter = 2;
//		} else if (month >= 7 && month <= 9) {
//			quarter = 3;
//		} else {
//			quarter = 4;
//		}
//		String str = "";
//		String firstDay = "";
//		// 设置本年的季
//		Calendar quarterCalendar = null;
//		switch (quarter) {
//			case 1: // 本年到现在经过了一个季度，在加上前4个季度
//				quarterCalendar = Calendar.getInstance();
//				quarterCalendar.set(Calendar.MONTH, 3);
//				quarterCalendar.set(Calendar.DATE, 1);
//				quarterCalendar.add(Calendar.DATE, -1);
//				str = sdf.format(quarterCalendar.getTime());
//				firstDay = str.substring(0, str.length() - 5) + "01-01";
//				break;
//			case 2: // 本年到现在经过了二个季度，在加上前三个季度
//				quarterCalendar = Calendar.getInstance();
//				quarterCalendar.set(Calendar.MONTH, 6);
//				quarterCalendar.set(Calendar.DATE, 1);
//				quarterCalendar.add(Calendar.DATE, -1);
//				str = sdf.format(quarterCalendar.getTime());
//				firstDay = str.substring(0, str.length() - 5) + "04-01";
//				break;
//			case 3:// 本年到现在经过了三个季度，在加上前二个季度
//				quarterCalendar = Calendar.getInstance();
//				quarterCalendar.set(Calendar.MONTH, 9);
//				quarterCalendar.set(Calendar.DATE, 1);
//				quarterCalendar.add(Calendar.DATE, -1);
//				str = sdf.format(quarterCalendar.getTime());
//				firstDay = str.substring(0, str.length() - 5) + "07-01";
//				break;
//			case 4:// 本年到现在经过了四个季度，在加上前一个季度
//				quarterCalendar = Calendar.getInstance();
//				str = sdf.format(quarterCalendar.getTime());
//				firstDay = str.substring(0, str.length() - 5) + "10-01";
//				break;
//		}
//		return firstDay;
	}

	/**
	 * 获取当前年第一天
	 * @return
	 */
	public static String getYearFirstDay(){
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_DAY);
		Calendar calendar = Calendar.getInstance();
//		String str = sdf.format(calendar.getTime());
//		return str.substring(0,str.length()-5)+"01-01";
		calendar.set(Calendar.MONTH,calendar.get(Calendar.MONTH) - 12);
		return sdf.format(calendar.getTime());
	}

	/**
	 * 获取一周内所有日期
	 * @return
	 */
	public static List<String> getWeekFullDay() {
		Calendar begin = Calendar.getInstance();// 得到一个Calendar的实例
		begin.setTime(new Date()); // 设置时间为当前时间
		begin.add(Calendar.DAY_OF_WEEK, -7);// 月份减1
		begin.add(Calendar.DATE, +1);// 日期加1
		Calendar end = Calendar.getInstance();
		Long startTime = begin.getTimeInMillis();
		Long endTime = end.getTimeInMillis();
		Long oneDay = 1000 * 60 * 60 * 24l;// 一天的时间转化为ms
		List dates = new ArrayList<>();
		Long time = startTime;
		int i = 0;
		while (time <= endTime) {
			Date d = new Date(time);
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			dates.add(i, df.format(d));
			i++;
			time += oneDay;
		}
		return dates;
	}

	/**
	 * 获取一月内所有日期
	 * @param day
	 * @return
	 */
	public static List<String> getMonthFullDay(int day) {
		Calendar begin = Calendar.getInstance();// 得到一个Calendar的实例
		begin.setTime(new Date()); // 设置时间为当前时间
		begin.add(Calendar.MONTH, -day);// 月份减1
		begin.add(Calendar.DATE, +1);// 日期加1
		Calendar end = Calendar.getInstance();
		Long startTime = begin.getTimeInMillis();
		Long endTime = end.getTimeInMillis();
		Long oneDay = 1000 * 60 * 60 * 24l;// 一天的时间转化为ms
		List dates = new ArrayList<>();
		Long time = startTime;
		int i = 0;
		while (time <= endTime) {
			Date d = new Date(time);
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			dates.add(i, df.format(d));
			i++;
			time += oneDay;
		}
		return dates;
	}

	/**
	 * 根据当前日期获取12月
	 * @return
	 */
	public static List<String> getYearFullMonth(){
		List<String> resultList = new ArrayList<>();
		try {

			Date d1 = new SimpleDateFormat("yyyy-MM").parse(getYearFirstDay());//定义起始日期

			Date d2 = new Date();//定义结束日期

			Calendar dd = Calendar.getInstance();//定义日期实例

			dd.setTime(d1);//设置日期起始时间

			while (dd.getTime().before(d2)) {//判断是否到结束日期

				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");

				String str = sdf.format(dd.getTime());

				resultList.add(str);//输出日期结果

				dd.add(Calendar.MONTH, 1);//进行当前日期月份加1

			}
		}catch (Exception e){
			e.printStackTrace();
		}
		return resultList;
	}

	/**
	 * 获取当年当前日期所有月份集合
	 * @return
	 */
	public static List<String> getFullMonth(){
		String year = getDate("yyyy");
		String month = getDate("MM");
		List<String> everyMonth = new ArrayList<>();
		String monStr;
		for (int i=1;i<=Integer.parseInt(month);i++){
			if (i<10){
				monStr = year+"-0"+i;
			} else {
				monStr = year+"-"+i;
			}
			everyMonth.add(monStr);
		}
		return everyMonth;
	}
	/**
	 * 获取当前时间24小时集合
	 * @return
	 */
	public static List<String> getHoursByDay(){
		List<String> dates = new ArrayList<>();
		try {
			Date day = new Date();
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd 00");
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH");
			String s = df.format(day);
			Date date = df.parse(s);
			dates.add(s);
			for (int i = 0; i < 23; i++) {
				Calendar cal = Calendar.getInstance();
				cal.setTime(date);
				cal.add(Calendar.HOUR, 1);
				date = cal.getTime();
				String s1 = format.format(date);
				dates.add(s1);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return dates;
	}

	/**
	 * 获取两个时间的所有小时数
	 * 时间格式必须是yyyy-MM-dd HH:mm:ss
	 * @param start
	 * @param end
	 * @return
	 */
	public static List<String> getBetweenDates(String start, String end) {
		List<String> result = new ArrayList<String>();
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH");
			Date start_date = sdf.parse(start);
			Date end_date = sdf.parse(end);
			Calendar tempStart = Calendar.getInstance();
			tempStart.setTime(start_date);
			Calendar tempEnd = Calendar.getInstance();
			tempEnd.setTime(end_date);
			while (tempStart.before(tempEnd)||tempStart.equals(tempEnd)) {
				result.add(sdf.format(tempStart.getTime()));
				tempStart.add(Calendar.HOUR, 1);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
//		Collections.reverse(result);
		return result;
	}
	/**
	 * 获取两个日期的所有天数
	 * 时间格式必须是yyyy-MM-dd HH:mm:ss
	 * @param start
	 * @param end
	 * @return
	 */
	public static List<String> getBetweenDateToDays(String start, String end) {
		List<String> result = new ArrayList<String>();
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			Date start_date = sdf.parse(start);
			Date end_date = sdf.parse(end);
			Calendar tempStart = Calendar.getInstance();
			tempStart.setTime(start_date);
			Calendar tempEnd = Calendar.getInstance();
			tempEnd.setTime(end_date);
			while (tempStart.before(tempEnd)||tempStart.equals(tempEnd)) {
				result.add(sdf.format(tempStart.getTime()));
				tempStart.add(Calendar.DAY_OF_YEAR, 1);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
//		Collections.reverse(result);
		return result;
	}

	private static List<Date> getHourlyInterval(Date fromDate, Date toDate) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(fromDate);

		List<Date> hourlyInterval = new ArrayList<>();
		hourlyInterval.add(calendar.getTime());

		while (calendar.getTime().before(toDate)) {
			calendar.add(Calendar.HOUR_OF_DAY, 1);
			hourlyInterval.add(calendar.getTime());
		}
		return hourlyInterval;
	}

//	public static void main(String[] args) {
//		Map<String,Object> timeMap = getHourList("2023-08-23 08:20:00","2023-08-23 18:00:00");
//		List<String> startTimes = (List<String>) timeMap.get("timeList");
//		List<String> times = startTimes.subList(0,startTimes.size()-1);
//		System.out.println(times);
//		List<String> endTimes = startTimes.subList(1,startTimes.size());
//		System.out.println(endTimes);
//		System.out.println(getSecondDiff("2023-08-23 08:20:00","2023-08-23 09:00:00"));
//	}


}
